﻿using LightCAD.Core.Elements;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using LightCAD.MathLib;
using static LightCAD.Core.Elements.LcPolyLine;
using System.Xml.Linq;

namespace LightCAD.Core
{
    /// <summary>
    /// 元素基类
    /// </summary>
    public abstract partial class LcElement : LcObject
    {

        private object _action;
        protected Box2 _boudingBox;
        private int ownerId;
        private int ownerAuth;

        private uint? colorValue;
        private string color = ValueFrom.ByLayer;
        private double? transparencyValue;
        private string transparency = ValueFrom.ByLayer;
        private string name;
        private string layer = "0";
        private LcLayer layerValue;
        private bool isGlobal = true;


        [JsonIgnore]
        public ElementType Type { get; protected set; }

        /// <summary>
        /// 宿主元素，用于在位编辑
        /// </summary>
        [JsonIgnore]
        public LcElement Host { get; set; }

        [DefaultValue("0")]
        public string Layer
        {
            get
            {
                return this.layer;
            }
            set
            {
                this.layer = value;
                this.layerValue = this.Document.Layers.GetByName(value);
                CreateIndex = 1;
            }
        }

        public int CreateIndex { get; set; } = -1;

        [DefaultValue(ValueFrom.ByLayer)]
        public string Color
        {
            get
            {
                return this.color;
            }
            set
            {
                this.color = value;
                this.colorValue = null;
            }
        }

        [DefaultValue(ValueFrom.ByLayer)]
        public string LineType { get; set; } = ValueFrom.ByLayer;

        [DefaultValue(ValueFrom.ByLayer)]
        public string LineWeight { get; set; } = ValueFrom.ByLayer;

        [DefaultValue(1.0)]
        public double LineTypeScale { get; set; } = 1.0;

        [DefaultValue(ValueFrom.ByLayer)]
        public string Transparency
        {
            get
            {
                return this.transparency;
            }
            set
            {
                this.transparency = value;
                this.transparencyValue = null;
            }
        }

        [DefaultValue(ValueFrom.ByColor)]
        public string PlotStyleName { get; set; } = ValueFrom.ByColor;

        [DefaultValue(true)]
        public bool Visible { get; set; } = true;
        public Dictionary<string, object> UserData { get; set; }

        public LcLayer GetLayerValue()
        {
            if (layerValue == null)
            {
                this.layer = this.Document.Layers.Where(x => x.IsStatus == true).FirstOrDefault().Name;
                layerValue = this.Document.Layers.GetByName(this.layer);
                CreateIndex = 1;
            }
            return layerValue;
        }

        public double GetTransparencyValue()
        {
            uint value = 0;
            if (this.Transparency == ValueFrom.ByLayer)
            {
                value = (uint)GetLayerValue().Transparency;
            }
            else
            {
                if (double.TryParse(this.transparency, out double c))
                {
                    value = (uint)c;
                }
            }
            if (value > 90)
            {
                value = 90;
            }
            if (value < 0)
            {
                value = 0;
            }
            transparencyValue = ((25500 - 255 * value) / 100);
            return transparencyValue.Value;
        }

        //要改为从全局接受颜色然后进行判断
        public uint GetColorValue()
        {
            if(this.isGlobal == true)
            {
                this.color = this.Document.Color;
                this.isGlobal = false;
            }
            if (this.color == ValueFrom.ByLayer)
            {
                colorValue = GetLayerValue().Color;
            }
            else if (this.color == ValueFrom.ByBlock)
            {
                colorValue = 0xFF000000;
            }
            else
            {
                string PATTERN = @"([^A-Fa-f0-9]|\s+?)+";
                if (uint.TryParse(this.color, out uint c))
                {
                    colorValue = c;
                }
                else if (Regex.IsMatch(this.color, PATTERN))
                {
                    var html = ColorTranslator.FromHtml(this.color);
                    colorValue = (uint)html.ToArgb();
                }
                else
                {
                    colorValue = 0xFF000000;
                }
            }
            uint alpha = (uint)GetTransparencyValue();
            string alphaValue = alpha.ToString("X");
            if (alpha != 0xFF)
            {
                string color = colorValue.Value.ToString("X");
                string result = alphaValue + color.Substring(2);
                colorValue = uint.Parse(result, System.Globalization.NumberStyles.HexNumber);
            }
            //}
            return colorValue.Value;
        }



        [JsonIgnore]
        public virtual bool IsSelected { get; set; }

        [JsonIgnore]
        public virtual bool IsDirty { get; set; }


        /// <summary>
        /// 运行时状态
        /// </summary>
        [JsonIgnore]
        public ElementStatus RtStatus { get; set; }

        public void SetStatus(ElementStatus status, bool state)
        {
            if (state)
                RtStatus |= status;
            else
                RtStatus &= ~status;
        }
        public bool HasStatus(ElementStatus status)
        {
            return (this.RtStatus & status) == status;
        }


        /// <summary>
        /// 运行时行为对象
        /// </summary>
        [JsonIgnore]
        public object RtAction
        {
            get
            {
                if (_action == null)
                {
                    LcDocument.ElementActions.TryGetValue(this.Type, out _action);
                }
                if (_action == null)
                {
                    throw new Exception($"Can't find Action. (ElementType={this.Type})");
                }
                return _action;
            }
        }




        public void SetVisible(bool visible, bool fireChangedEvent = true)
        {
            if (this.Visible == visible) return;
            //if (fireChangedEvent) OnPropertyChangedBefore(nameof(Visible), this.Visible, visible);
            var oldValue = this.Visible;
            this.Visible = visible;
            if (fireChangedEvent) OnPropertyChangedAfter(nameof(Visible), oldValue, this.Visible);
        }
        [JsonIgnore]
        public Box2 BoundingBox
        {
            get
            {
                if (this._boudingBox == null)
                {
                    this._boudingBox = GetBoundingBox();
                }
                return this._boudingBox;
            }
        }
  
        /// <summary>
        /// 求直线与其他实体的交点
        /// </summary>
        /// <param name="line2D"></param>
        /// <returns></returns>

        public List<Vector2> GetCrossVectorByElement(LcElement element)
        {
            List<Vector2> ps= new List<Vector2>();
            if (element is LcLine)
            {
                if(this.GetCrossVectorByLine((element as LcLine).Line) != null)
                {
                    ps.AddRange(this.GetCrossVectorByLine((element as LcLine).Line));
                }
            }
            if (element is LcArc)
            {
                if (this.GetCrossVectorByArc((element as LcArc).Arc) != null)
                {
                    ps.AddRange(this.GetCrossVectorByArc((element as LcArc).Arc));
                }

            }
            if (element is LcCircle)
            {
                if (this.GetCrossVectorByCircle((element as LcCircle).Circle) != null)
                {
                    ps.AddRange(this.GetCrossVectorByCircle((element as LcCircle).Circle));
                }
                   
            }
            if (element is LcPolyLine)
            {
                LcPolyLine lcPolyLine =element as LcPolyLine;
                List<Vector2> points1 = new List<Vector2>();
                List<Vector2> points2 = new List<Vector2>();
                if (lcPolyLine.Curve2ds[0].Type == Curve2dType.Line2d)
                {

                    //LcLine lcLine = new LcLine();
                    //lcLine.Start = lcpolyline1.Start;
                    //lcLine.End = lcpolyline1.End;
                    //lcLine.Start = LcPolyLine.GetStart(lcPolyLine.Curve2ds[0]);
                    //lcLine.End = LcPolyLine.GetEnd(lcPolyLine.Curve2ds[0]); 
                    var lcpolyline1 = lcPolyLine.Curve2ds[0] as Line2d;
                    points1.AddRange(this.GetCrossVectorByLine(lcpolyline1));
                }
                else //如果多段线第一段是圆弧
                {
                    var lcpolyline1 = lcPolyLine.Curve2ds[0] as Arc2d;
                    points1.AddRange(this.GetCrossVectorByArc(lcpolyline1));
                }
                if (lcPolyLine.Curve2ds.LastOrDefault().Type == Curve2dType.Line2d) //如果多段线最后一段是线
                {
                    var lcpolyline2 = lcPolyLine.Curve2ds.Last() as Line2d;
                    points2.AddRange(this.GetCrossVectorByLine(lcpolyline2));
                }
                else   //如果多段线最后一段是圆弧
                {
                    var lcpolyline2 = lcPolyLine.Curve2ds.Last() as Arc2d;
                    points2.AddRange(this.GetCrossVectorByArc(lcpolyline2));
                }
                ps.AddRange(points1);
                ps.AddRange(points2);
                //var wcsp1 = this.vportRt.ConvertScrToWcs(this.vportRt.PointerMovedPosition.ToVector2d());
                ////LcPolyLine lcPolyLine = (LcPolyLine)element2;
                //double ds = Vector2.Distance(wcsp1, LcPolyLine.GetStart(lcPolyLine.Curve2ds[0]));
                //double de = Vector2.Distance(wcsp1, LcPolyLine.GetEnd(lcPolyLine.Curve2ds.Last()));
                //if (ds < de)
                //{

                //}
            }
            return ps;
        }
        public virtual List<Vector2> GetCrossVectorByLine(Line2d ele)
        {
            return new List<Vector2>();
        }
        public virtual Vector2 LineCrossLine(LcLine ele)    
        {
            return new Vector2();
        }
        public virtual Vector2 LineCrossLine(Line2d ele)
        {
            return new Vector2();
        }
        public virtual List<Vector2> GetCrossVectorByArc(Arc2d ele)
        {
            return new List<Vector2>();
        }
        public virtual List<Vector2> GetCrossVectorByCircle(Circle2d ele)
        {
            return new List<Vector2>();
        }
        public virtual bool PointInElement(Vector2 point, double epsilon = 0.001)
        {
            return false;
        }
    
        public virtual LcElement ApplyMatrix(Matrix3 matrix)
        {
            return this;
        }
        public virtual Box2 GetBoundingBox()
        {
            return new Box2();
        }
        public virtual Box2 GetBoundingBox(Matrix3 matrix)
        {
            return new Box2();
        }

        public void ResetBoundingBox()
        {
            this._boudingBox = null;
        }
        public virtual void Translate(double dx, double dy)
        {
        }
        public virtual void Translate(Vector2 vec)
        {
            this.Translate(vec.X, vec.Y);
        }
        public virtual void CopyStyle(LcElement src)
        {
            this.Layer = src.Layer;
            this.Color = src.Color;
            this.LineType = src.LineType;
            this.LineTypeScale = src.LineTypeScale;
            this.LineWeight = src.LineWeight;
            this.Transparency = src.Transparency;
            this.PlotStyleName = src.PlotStyleName;
        }
        public virtual void Copy(LcElement src)
        {
            base.Copy(src);
            this.Visible = src.Visible;
            CopyStyle(src);
        }


        public virtual void Move(Vector2 startPoint, Vector2 endPoint)
        {
        }
        public virtual void Scale(Vector2 basePoint, double scaleFactor)
        {

        }
        public virtual void Scale(Vector2 basePoint, Vector2 scaleVector)
        {

        }
        public virtual void Rotate(Vector2 basePoint, double rotateAngle)
        {

        }
        public virtual void Mirror(Vector2 axisStart, Vector2 axisEnd)
        {
            
        }

        protected override void OnPropertyChanged(string propertyName, LcPropertyGroup extPropGroup, LcProperty extProp)
        {
            ResetBoundingBox();
        }
        /// <summary>
        /// 是否和盒子相交
        /// </summary>
        /// <param name="testBox">测试盒子</param>
        /// <param name="eleMatrix">元素的转换矩阵</param>
        /// <returns></returns>
        public virtual bool IntersectWithBox(Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            return false;
        }
        public virtual bool IntersectWithBox1(LcArc lcARC,Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            return false;
        }
        /// <summary>
        /// 是否被盒子包含
        /// </summary>
        /// <param name="testBox">测试盒子</param>
        /// <param name="eleMatrix">元素的转换矩阵</param>
        /// <returns></returns>
        public virtual bool IncludedByBox(Polygon2d testPoly, List<RefChildElement> includedChildren = null)
        {
            return false;
        }

        public abstract LcElement Clone();

        /// <summary>
        /// 此方法获取元素的几何曲线，用于各类计算
        /// </summary>
        /// <returns></returns>
        public virtual Curve2d[] GetCurves()
        {
            return new Curve2d[0];
        }
        public virtual Curve2d GetCurve()
        {
            return null;
        }
    }

    public class RefChildElement
    {
        public LcElement Element { get; set; }
        public IElementContainerRef RefObject { get; set; }

        public RefChildElement(LcElement element, IElementContainerRef refObject)
        {
            Element = element;
            RefObject = refObject;
        }
    }


}